package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.AttributeSet.FontAttribute;

import svm.Interval;
import svm.Session.Activity;
import utils.Utils;
import au.AU.Label;

public class IntervalView extends JFrame {

	private JPanel controls;
	private List<Interval> intervals;
	private JButton nextBtn;
	private JButton prevBtn;
	private JButton zoomInBtn;
	private JButton zoomOutBtn;
	private JLabel infoLabel;
	private int actFirstFrame;
	private int actZoom;
	private Graph actGraph = null;
	
	public IntervalView(List<Interval> intervals) {
		
		System.out.println("Created view with " + intervals.size() + " intervals.");
		this.intervals = intervals;
		
		// frame 
		setBounds(10, 100, 1200, 400);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(null);
		setVisible(true);
		
		// controls
		controls = new JPanel();
		controls.setBounds(0, S.CONTROLS_LEVEL, 1000, 40);
		controls.setLayout(null);
		add(controls);
		infoLabel = new JLabel();
		nextBtn = new JButton("->");
		prevBtn = new JButton("<-");
		zoomInBtn = new JButton("+");
		zoomOutBtn = new JButton("-");
		infoLabel.setBounds(300, 0, 400, 40);
		nextBtn.setBounds(70, 0, 70, 40);
		prevBtn.setBounds(0, 0, 70, 40);
		zoomInBtn.setBounds(140, 0, 70, 40);
		zoomOutBtn.setBounds(210, 0, 70, 40);
		controls.add(nextBtn);
		controls.add(prevBtn);
		controls.add(zoomInBtn);
		controls.add(zoomOutBtn);
		controls.add(infoLabel);
		nextBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				displayGraph(actFirstFrame + 1, actZoom);
			}
		});
		prevBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				displayGraph(actFirstFrame - 1, actZoom);
			}
		});
		zoomInBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				displayGraph(actFirstFrame, actZoom + 1);
			}
		});
		zoomOutBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				displayGraph(actFirstFrame, actZoom - 1);
			}
		});
		
		
		displayGraph(0, 7);
	}
	
	public void displayGraph(int from, int zoom) {
		if(from >= intervals.size() || from < 0) return;
		int to = ( (from + zoom) > intervals.size() ? intervals.size() : (from + zoom) );
		System.out.println("drawing graph of intervals " + from + " - " + to + "...");
		infoLabel.setText("Displaying intervals " + from + " - " + to + " out of " + intervals.size());
		if(actGraph != null) remove(actGraph);
    	repaint();
		this.actFirstFrame = from;
		this.actZoom = zoom;
		HashMap<Label, PointData> p1 = new HashMap<Label, PointData>();
		actGraph = new Graph(intervals.subList(from, to));
		actGraph.setBounds(0, S.GRAPH_LEVEL, 5000, S.GRAPH_WHOLE_HEIGHT);
		add(actGraph);
    	//repaint();
    	actGraph.repaint();
		System.out.println("graph done");
	}
	
	public static Color AUColor(Label label) {
		if(label == Label.LFAU_12) return Color.GREEN;
		else if(label == Label.LFAU_23) return Color.ORANGE;
		else if(label == Label.LFAU_26) return Color.CYAN;
		else if(label == Label.UFAU_1) return Color.BLUE;
		else if(label == Label.UFAU_2) return Color.RED;
		else return null;
	}
	
	public class Graph extends JComponent {
		
		private static final long serialVersionUID = 1L;
		private List<GraphComponent> components = new ArrayList<GraphComponent>();
		private List<Interval> intervals;

		public Graph(List<Interval> intervals) {
			this.intervals = intervals;
            //setPreferredSize(new Dimension(600, 200));
		}
		
		@Override
		public void paintComponent(Graphics g) {
            super.paintComponents(g);
            

			int offset;
			for (int i = 0; i < intervals.size(); i++) {
				
				offset = i * (S.GRAPH_COMPONENT_WIDTH+1);
				
				components.add(new GraphComponent(intervals.get(i), offset));

				System.out.println(components.get(i).points.get(Label.LFAU_12));
				
	            // print component
				g.setColor(Color.DARK_GRAY);
				g.fillRect(offset, 0, S.GRAPH_COMPONENT_WIDTH, S.GRAPH_ACTIVITY_HEIGHT);
				g.setFont(new Font("font2", Font.BOLD, 12));
				int j = 0;
				for(Activity activity: intervals.get(i).getActivities()) {
					int actLevel = 15 + (j/2)*20;
					g.setColor(Color.WHITE);
					g.drawChars(activity.name.toCharArray(), 0, activity.name.length(), offset + 8 + ( j%2==1 ? S.GRAPH_COMPONENT_WIDTH/2 : 0 ), actLevel);
					j++;
				}
				
				g.setColor(Color.BLACK);
				g.fillRect(offset, S.GRAPH_ACTIVITY_HEIGHT + 1, S.GRAPH_COMPONENT_WIDTH, S.GRAPH_HEIGHT);
				g.setColor(Color.DARK_GRAY);
				g.fillRect(offset, (S.GRAPH_ACTIVITY_HEIGHT + S.GRAPH_HEIGHT + 2), S.GRAPH_COMPONENT_WIDTH, (S.GRAPH_TIME_HEIGHT - 1));
				g.setFont(new Font("font1", 5, 10));
				for (Label label : Label.values()) {
					g.setColor(IntervalView.AUColor(label));
					if (components.get(i).points.containsKey(label)) {
						
						// points
						PointData p = components.get(i).points.get(label);
						g.drawRect(p.xPos, p.yPos, GraphComponent.DOT_SIZE, GraphComponent.DOT_SIZE);
						if(false) // TODO replace with variable and checkbox
						g.drawChars(label.toString().toCharArray(), 0, label
								.toString().length(), p.textXPos, p.textYPos);
						
						// time
						g.setColor(Color.WHITE);
						SimpleDateFormat df = new SimpleDateFormat("HH-mm-ss");
						String time1 = df.format(intervals.get(i).getRows().get(0).time);
						String time2 = df.format(intervals.get(i).getRows().get(intervals.get(i).getRows().size() - 1).time);
						g.drawChars(time1.toCharArray(), 0, time1.toString().length(), offset + 5, (S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT + 15));
						g.drawChars(time2.toCharArray(), 0, time1.toString().length(), offset + S.GRAPH_COMPONENT_WIDTH - 50, (S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT + 15));
					}
				}

				if(i > 0) {
					for(Label label: Label.values()) {
						HashMap<Label, PointData> p1 = this.components.get(i-1).getPoints();
						HashMap<Label, PointData> p2 = this.components.get(i).getPoints();
						if(p1.containsKey(label) && p2.containsKey(label)) {
							int x1 = p1.get(label).xPos;
							int y1 = p1.get(label).yPos;
							int x2 = p2.get(label).xPos;
							int y2 = p2.get(label).yPos;
							g.setColor(IntervalView.AUColor(label));
							g.drawLine(x1, y1, x2, y2);
						}
					}
				}
			}
		}
	}
	
    public class GraphComponent {

        private static final long serialVersionUID = 1L;
		public static final int DOT_SIZE = 5;
		private Interval interval;
		private List<Integer> yPosList = new ArrayList<Integer>();
		private List<Integer> xPosList = new ArrayList<Integer>();
		private HashMap<Label, PointData> points = new HashMap<Label, PointData>();

		public GraphComponent(Interval interval, int offset) {
        	this.interval = interval;
            setPreferredSize(new Dimension(S.GRAPH_COMPONENT_WIDTH, S.GRAPH_WHOLE_HEIGHT));
        	generateData(offset);
        }

        public HashMap<Label, PointData> getPoints() {
			return points;
		}       
        
        private void generateData(int offset) {
        	List<String> activeLabels = Utils.labelsToStringList();
			for(Label label: Label.values()) {
				double level = interval.getAvgAu(label);
				if(activeLabels.contains(label.toString())) {
					int xPos = generateXPos() + offset;
					int yPos = S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT - ((S.GRAPH_HEIGHT / 100) * (int)(level));
					int textYPos = S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT - ((S.GRAPH_HEIGHT / 100) * generateYPos((int)(level)));
					int textXPos = xPos+5+(DOT_SIZE/2);
					points.put(label, new PointData(xPos, yPos, textXPos, textYPos));
				}
			}
        }
        
        private int generateXPos() {
        	int unit = 20;
        	int max = 0;
        	if(xPosList.size() > 0) {
        		max = Collections.max(xPosList);
        	}
        	int xPos = max + unit;
        	xPosList.add(xPos);
        	return xPos > (S.GRAPH_COMPONENT_WIDTH - 10) ? (S.GRAPH_COMPONENT_WIDTH - 10) : xPos;
        }
        
        private int generateYPos(int level) {
        	int yPos;
        	int unit = 5;
        	if(yPosList.contains(level)) {
        		return generateYPos(level - unit);
        	} else {
        		yPos = level;
        	}
        	yPosList.add(yPos);
        	return yPos > (S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT - 10) ? (S.GRAPH_HEIGHT + S.GRAPH_ACTIVITY_HEIGHT - 10) : yPos;
        }

    }
    public class PointData {
    	public int xPos, yPos, textXPos, textYPos;
    	public PointData(int xPos, int yPos, int textXPos, int textYPos) {
    		this.xPos = xPos;
    		this.yPos = yPos;
    		this.textXPos = textXPos;
    		this.textYPos = textYPos;
		}
    	@Override
    	public String toString() {
    		return new String(xPos + ", " + yPos + ", " + textXPos + ", " + textYPos);
    	}
    }

}
